package net.callumtaylor.asynchttp.obj;

import java.io.IOException;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.Buffer;
import okio.BufferedSink;
import okio.ForwardingSink;
import okio.Okio;
import okio.Sink;

/**
 * Decorates an OkHttp request body to count the number of bytes written when writing it. Can
 * decorate any request body, but is most useful for tracking the upload progress of large
 * multipart requests.
 *
 * @author Leo Nikkilä
 */
public class CountingRequestBody extends RequestBody
{
	protected RequestBody delegate;
	protected Listener listener;

	protected CountingSink countingSink;

	public CountingRequestBody(RequestBody delegate, Listener listener)
	{
		this.delegate = delegate;
		this.listener = listener;
	}

	@Override public MediaType contentType()
	{
		return delegate.contentType();
	}

	@Override public long contentLength()
	{
		try
		{
			return delegate.contentLength();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

		return 0;
	}

	@Override public void writeTo(BufferedSink sink) throws IOException
	{
		BufferedSink bufferedSink;

		countingSink = new CountingSink(sink);
		bufferedSink = Okio.buffer(countingSink);

		delegate.writeTo(bufferedSink);

		bufferedSink.flush();
	}

	protected final class CountingSink extends ForwardingSink
	{
		private long bytesWritten = 0;

		public CountingSink(Sink delegate)
		{
			super(delegate);
		}

		@Override public void write(Buffer source, long byteCount) throws IOException
		{
			Buffer copy = new Buffer();
			source.copyTo(copy, 0, byteCount);

			super.write(source, byteCount);

			bytesWritten += byteCount;
			listener.onRequestProgress(copy.readByteArray(), byteCount, bytesWritten, contentLength());
		}
	}

	public static interface Listener
	{
		public void onRequestProgress(byte[] buffer, long bufferCount, long bytesWritten, long contentLength);
	}
}
